package com.rolerealm.service.impl;

import com.rolerealm.service.LLMService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.time.Duration;

/**
 * 基于 OpenAI Chat Completions 的 LLM 实现
 */
@Slf4j
@Service
public class OpenAiLLMServiceImpl implements LLMService {

    @Value("${llm.openai.apiKey:}")
    private String apiKey;

    @Value("${llm.openai.baseUrl:https://api.openai.com}")
    private String baseUrl;

    @Value("${llm.openai.timeoutSeconds:30}")
    private int timeoutSeconds;

    private final HttpClient httpClient = HttpClient.newBuilder()
            .connectTimeout(Duration.ofSeconds(10))
            .build();

    @Override
    public String infer(String prompt, String languageOrModel) {
        if (apiKey == null || apiKey.isBlank()) {
            log.warn("OpenAI API Key 未配置，回退到简单回声");
            return "AI回复：" + (prompt == null ? "" : prompt);
        }

        // 优先使用通义千问模型
        String[] models = {"qwen-max", "qwen-plus", "qwen-turbo"};
        String model = (languageOrModel == null || languageOrModel.isBlank()) ? models[0] : languageOrModel;
        String url = baseUrl.endsWith("/") ? (baseUrl + "v1/chat/completions") : (baseUrl + "/v1/chat/completions");

        String body = "{\n" +
                "  \"model\": \"" + escape(model) + "\",\n" +
                "  \"messages\": [\n" +
                "    {\"role\": \"system\", \"content\": \"You are RoleRealm AI.\"},\n" +
                "    {\"role\": \"user\", \"content\": " + toJsonString(prompt) + "}\n" +
                "  ],\n" +
                "  \"temperature\": 0.7\n" +
                "}";

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(url))
                .timeout(Duration.ofSeconds(Math.max(5, timeoutSeconds)))
                .header("Authorization", "Bearer " + apiKey)
                .header("Content-Type", "application/json")
                .POST(HttpRequest.BodyPublishers.ofString(body, StandardCharsets.UTF_8))
                .build();

        // 尝试多个模型
        for (String tryModel : models) {
            try {
                String tryBody = "{\n" +
                        "  \"model\": \"" + escape(tryModel) + "\",\n" +
                        "  \"messages\": [\n" +
                        "    {\"role\": \"system\", \"content\": \"You are RoleRealm AI.\"},\n" +
                        "    {\"role\": \"user\", \"content\": " + toJsonString(prompt) + "}\n" +
                        "  ],\n" +
                        "  \"temperature\": 0.7\n" +
                        "}";

                log.debug("尝试调用模型: {}, URL: {}, Body: {}", tryModel, url, tryBody);

                HttpRequest tryRequest = HttpRequest.newBuilder()
                        .uri(URI.create(url))
                        .timeout(Duration.ofSeconds(Math.max(5, timeoutSeconds)))
                        .header("Authorization", "Bearer " + apiKey)
                        .header("Content-Type", "application/json")
                        .POST(HttpRequest.BodyPublishers.ofString(tryBody, StandardCharsets.UTF_8))
                        .build();

                HttpResponse<String> response = httpClient.send(tryRequest, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8));
                log.debug("模型 {} 响应状态: {}, 响应体: {}", tryModel, response.statusCode(), response.body());
                
                if (response.statusCode() / 100 == 2) {
                    String resp = response.body();
                    String content = extractContentFromChatCompletions(resp);
                    if (content != null && !content.isBlank()) {
                        log.info("成功使用模型: {}", tryModel);
                        return content;
                    }
                } else {
                    log.warn("模型 {} 调用失败，status={} body={}", tryModel, response.statusCode(), response.body());
                }
            } catch (Exception e) {
                log.warn("模型 {} 调用异常: {}", tryModel, e.getMessage());
            }
        }
        
        log.error("所有模型都调用失败，回退到简单回声");
        return fallback(prompt);
    }

    private String fallback(String prompt) {
        return "AI回复：" + (prompt == null ? "" : prompt);
    }

    private static String toJsonString(String text) {
        if (text == null) return "\"\"";
        String esc = text.replace("\\", "\\\\").replace("\"", "\\\"").replace("\n", "\\n");
        return "\"" + esc + "\"";
    }

    private static String escape(String s) {
        return s == null ? "" : s.replace("\"", "");
    }

    // 非严格 JSON 解析；仅提取第一条 choice 的 message.content
    private static String extractContentFromChatCompletions(String json) {
        if (json == null) return null;
        int idx = json.indexOf("\"message\"");
        if (idx < 0) return null;
        int cidx = json.indexOf("\"content\"", idx);
        if (cidx < 0) return null;
        int colon = json.indexOf(':', cidx);
        if (colon < 0) return null;
        int start = json.indexOf('"', colon + 1);
        if (start < 0) return null;
        StringBuilder sb = new StringBuilder();
        boolean escape = false;
        for (int i = start + 1; i < json.length(); i++) {
            char ch = json.charAt(i);
            if (escape) {
                switch (ch) {
                    case 'n': sb.append('\n'); break;
                    case 'r': sb.append('\r'); break;
                    case 't': sb.append('\t'); break;
                    case '"': sb.append('"'); break;
                    case '\\': sb.append('\\'); break;
                    default: sb.append(ch); break;
                }
                escape = false;
            } else {
                if (ch == '\\') { escape = true; continue; }
                if (ch == '"') break;
                sb.append(ch);
            }
        }
        return sb.toString();
    }
}


